using System;
using System.Collections.Generic;
using Be.Timvw.Framework.Domain.Ranges;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Be.Timvw.Framework.Domain.Effectivity
{
    /// <summary>
    /// Specifications for when an effectivity is added to a temporal
    /// </summary>
    [TestClass]
    public class WhenAddingElementToTemporal : TemporalUnitTest
    {
        /// <summary>
        /// The first added effectivity should be valid till end of time.
        /// </summary>
        [TestMethod]
        public void ShouldMakeFirstEffectivityValidTillEndOfTime()
        {
            Temporal<string> temporal = new Temporal<string>();
            temporal.Modify("2000-01", new DateTime(2000, 1, 1));

            IList<IEffectivity<string>> expectedEffectivities = new List<IEffectivity<string>>();
            expectedEffectivities.Add(new Effectivity<string>("2000-01", new Range<DateTime>(new DateTime(2000, 1, 1), DateTime.MaxValue)));

            AssertEffectivities.AreEqual(expectedEffectivities, temporal.Effectivities);
        }

        /// <summary>
        /// When the new effectivity begins before all already existing effectivities, it is inserted at the beginning. 
        /// </summary>
        [TestMethod]
        public void ShouldAddNewEffectivityAtTheBeginningWhenFromIsBeforeAllAlreadyExistingEffectivities()
        {
            Temporal<string> effectivityManager = new Temporal<string>();
            effectivityManager.Modify("2000-01", new DateTime(2000, 1, 1));
            effectivityManager.Modify("1999-01", new DateTime(1999, 1, 1));

            IList<IEffectivity<string>> expectedEffectivities = new List<IEffectivity<string>>();
            expectedEffectivities.Add(new Effectivity<string>("1999-01", new Range<DateTime>(new DateTime(1999, 1, 1), new DateTime(2000, 1, 1).AddTicks(-1))));
            expectedEffectivities.Add(new Effectivity<string>("2000-01", new Range<DateTime>(new DateTime(2000, 1, 1), DateTime.MaxValue)));

            AssertEffectivities.AreEqual(expectedEffectivities, effectivityManager.Effectivities);
        }

        /// <summary>
        /// When the new effectivity starts in an existing effectivity, the existing effectivity should be shortened.
        /// </summary>
        [TestMethod]
        public void ShouldShortenExistingEffectivityWhenFromIsInPeriod()
        {
            Temporal<string> effectivityManager = new Temporal<string>();
            effectivityManager.Modify("1999-01", new DateTime(1999, 1, 1));
            effectivityManager.Modify("2000-01", new DateTime(2000, 1, 1));

            IList<IEffectivity<string>> expectedEffectivities = new List<IEffectivity<string>>();
            expectedEffectivities.Add(new Effectivity<string>("1999-01", new Range<DateTime>(new DateTime(1999, 1, 1), new DateTime(2000, 1, 1).AddTicks(-1))));
            expectedEffectivities.Add(new Effectivity<string>("2000-01", new Range<DateTime>(new DateTime(2000, 1, 1), DateTime.MaxValue)));

            AssertEffectivities.AreEqual(expectedEffectivities, effectivityManager.Effectivities);
        }

        /// <summary>
        /// When the new effectivity starts in an existing effectivity, 
        /// the new effectivity should be valid till the end of the already existing effectivity.
        /// </summary>
        [TestMethod]
        public void ShouldMakeNewEffectivityPeriodTillEndOfAlreadyExistingEffectivityPeriodEnd()
        {
            Temporal<string> effectivityManager = new Temporal<string>();
            effectivityManager.Modify("1999-01", new DateTime(1999, 1, 1));
            effectivityManager.Modify("2001-01", new DateTime(2001, 1, 1));
            effectivityManager.Modify("2000-01", new DateTime(2000, 1, 1));

            IList<IEffectivity<string>> expectedEffectivities = new List<IEffectivity<string>>();
            expectedEffectivities.Add(new Effectivity<string>("1999-01", new Range<DateTime>(new DateTime(1999, 1, 1), new DateTime(2000, 1, 1).AddTicks(-1))));
            expectedEffectivities.Add(new Effectivity<string>("2000-01", new Range<DateTime>(new DateTime(2000, 1, 1), new DateTime(2001, 1, 1).AddTicks(-1))));
            expectedEffectivities.Add(new Effectivity<string>("2001-01", new Range<DateTime>(new DateTime(2001, 1, 1), DateTime.MaxValue)));

            AssertEffectivities.AreEqual(expectedEffectivities, effectivityManager.Effectivities);
        }

        /// <summary>
        /// An existing effectivity that is about to be shortened so that the end is before the begin, should be removed.
        /// </summary>
        [TestMethod]
        public void ShouldRemoveExistingEffectivityIfNewEffectivityOverlapsItsWholeValidityPeriod()
        {
            Temporal<string> effectivityManager = new Temporal<string>();
            effectivityManager.Modify("1999-01", new DateTime(1999, 1, 1));
            effectivityManager.Modify("2000-01", new DateTime(2000, 1, 1));
            effectivityManager.Modify("2000-04", new DateTime(2000, 4, 1));
            effectivityManager.Modify("2001-01", new DateTime(2001, 1, 1));
            effectivityManager.Modify("2000-01-x", new DateTime(2000, 1, 1));

            IList<IEffectivity<string>> expectedEffectivities = new List<IEffectivity<string>>();
            expectedEffectivities.Add(new Effectivity<string>("1999-01", new Range<DateTime>(new DateTime(1999, 1, 1), new DateTime(2000, 1, 1).AddTicks(-1))));
            expectedEffectivities.Add(new Effectivity<string>("2000-01-x", new Range<DateTime>(new DateTime(2000, 1, 1), new DateTime(2000, 4, 1).AddTicks(-1))));
            expectedEffectivities.Add(new Effectivity<string>("2000-04", new Range<DateTime>(new DateTime(2000, 4, 1), new DateTime(2001, 1, 1).AddTicks(-1))));
            expectedEffectivities.Add(new Effectivity<string>("2001-01", new Range<DateTime>(new DateTime(2001, 1, 1), DateTime.MaxValue)));

            AssertEffectivities.AreEqual(expectedEffectivities, effectivityManager.Effectivities);
        }
    }
}